package com.solidumgame.martillo.hammer
{
	import Box2D.Dynamics.b2Body;
	
	import com.greensock.TweenMax;
	import com.greensock.easing.Linear;
	import com.pblabs.box2D.CollisionEvent;
	import com.pblabs.engine.PBE;
	import com.pblabs.engine.components.AnimatedComponent;
	import com.pblabs.engine.core.InputMap;
	import com.pblabs.engine.entity.PropertyReference;
	import com.solidumgame.martillo.hammer.events.HammerGenericEvent;
	import com.solidumgame.martillo.hammer.events.HammerSpeedEvent;
	import com.solidumgame.martillo.tablewood.events.TableWoodGenericEvent;
	
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.media.Sound;
	import flash.media.SoundLoaderContext;
	import flash.net.URLRequest;
	
	/**
	 * 
	 * @author martin
	 * 
	 */
	public class HammerLogicComponent extends AnimatedComponent
	{	
		public var point:Point;
		public var movePoint:Point;
		public var knockPoint:Point;
		public var tweenHorizontalMove:TweenMax;
		public var tweenKnockMove:TweenMax;
		public var tweenGoUpMove:TweenMax;
		public var tweenGoLeft:TweenMax;
		public var sound:HammerSoundComponent;
		public var allowedKnock:Boolean;
		public var allowedMove:Boolean;
		
		protected var wentDown:Boolean = false;
		protected var collidedWithNail:Boolean = false;
		protected var speed:Number = 3;
		
			
		/**
		 * Constructor de HammerLogicComponent
		 * 
		 */		
		public function HammerLogicComponent()
		{	
			super();
		}
		
		/**
		 * Se agrega Listener de evento de actualización de velocidad.
		 * Es la velocidad a la cual el martillo realiza el movimiento horizontal.
		 * Se asigna false al atributo registerForUpdates, lo cual hace que no se llame al método onFrame.
		 */		
		override protected function onAdd():void{
			super.onAdd();
			this.registerForUpdates = false;
			PBE.mainStage.addEventListener(HammerSpeedEvent.SPEED_UPDATE_EVENT,updateSpeed);
		}		
			
		/**
		 * Manejador de evento de actualización de velocidad.
		 * Se asigna al atributo speed de HammerLogicComponent el valor de la variable speed del evento disparado. 
		 * 
	     * @param e evento de actualización de velocidad
	     * 
		 */		
		protected function updateSpeed(e:HammerSpeedEvent):void{
			this.speed = e.speed;
		}
		
		/**
		 * Se agregan 2 Listeners.
		 * TABLEWOOD_TRHOW_EXIT es un evento que se dispara cuando TableWood es despedida de la escena.
		 * TABLEWOOD_ENTER_EVENT es un evento que se dispara cuando TableWood se agrega a la escena.
		 */		
		override protected function onReset():void{
			super.onReset();
			
			PBE.mainStage.addEventListener(TableWoodGenericEvent.TABLEWOOD_TRHOW_EXIT,stopHammer);
			PBE.mainStage.addEventListener(TableWoodGenericEvent.TABLEWOOD_ENTER_EVENT,move);
		}
		
		/**
		 * Manejador de evento que se dispara cuando TableWood se agrega a la escena.
		 * Se establece en true el atributo allowedKnock, el cual permite que el Hammer realice golpes.
		 * Se asigna al atributo movePoint la posición del componente Spatial.
		 * Se llama al método updatePoint pasando como parámetro movePoint.
		 * Se establece en true el atributo registerForUpdates, lo cual hace que se llame al método onFrame.
		 * Se crea un TweenMax (para realizar movimiento) y se asigna al atributo tweenHorizontalMove. Este movimiento es 
		 * el que realiza el Hammer horizontalmente en la pantalla, de izquierda a derecha y luego regresando de derecha 
		 * a izquierda. 
		 * Dicho TweenMax realiza un movimiento desde movePoint hasta la posición x:200, y:0, el tiempo en que realiza el
		 * movimiento está determinado por el atributo Speed. yoyo:true para que también regrese hacia la posición de 
		 * partida luego de llegar a la posición x:200, y:0.
		 * Se agrega Listener de presionado de tecla.
		 * 
		 * @param e evento de TableWood.
		 * 
		 * @see updatePoint
		 */		
		public function move(e:TableWoodGenericEvent):void
		{	
			allowedKnock = true;
			movePoint = owner.getProperty(new PropertyReference("@Spatial.position"));
			updatePoint(movePoint);
			this.registerForUpdates = true;
			tweenHorizontalMove = TweenMax.to(movePoint,speed,{x:200,y:0, ease:Linear.easeNone, yoyo:true, repeat:-1, onUpdate:updatePoint(movePoint)});
			PBE.mainStage.addEventListener(KeyboardEvent.KEY_DOWN,knock);
			
		}
		
		/**
		 * 
		 * @param point punto que contiene una coordenada en x e y.
		 * 
		 */		
		private function updatePoint(point:Point):void{
			this.point = point;
		}
		
		/**
		 * Manejador de evento de presionado de tecla.
		 * Si la tecla presionada es la barra espaciadora y el atributo allowedKnock está establecido en true se 
		 * realizan las siguientes acciones:
		 * Se establece en false allowedKnock para que Hammer no pueda realizar un golpe mientras está realizando uno.
		 * 
		 * 
		 * Se pausa el movimiento horizontal de lado a lado de Hammer.
		 * Se asigna al atributo knockPoint la posición de Spatial.
		 * Se llama al método updatePoint pasando por parámetro el atributo knockPoint.
		 * Se crea un TweenMax para el movimiento vertical que debe realizar Hammer durante el golpe. El mismo
		 * lo realiza desde la posición knockPoint, en 0.4 segundos, hasta la posición y:162 manteniendo el mismo valor 
		 * en x. Cuando se completa el movimiento se llama al método goUp.
		 * Se agrega Listener de colisión de Hammer con Nail.
		 * 
		 * @param e evento de teclado
		 * 
		 */		
		public function knock(e:KeyboardEvent):void
		{	
			if(e.keyCode==32 && allowedKnock!= false)
			{	
				allowedKnock=false;
				collidedWithNail = false;
				wentDown = true;
				tweenHorizontalMove.pause();
				knockPoint = owner.getProperty(new PropertyReference("@Spatial.position"));
				updatePoint(knockPoint);
				tweenKnockMove = TweenMax.to(knockPoint,0.4,{y:162, ease:Linear.easeNone, onComplete:goUp});
				if(owner)
					owner.eventDispatcher.addEventListener(CollisionEvent.COLLISION_EVENT,nailHit);
			}
		}
		
		
		/**
		 * Manejador de evento que se dispara cuando TableWood es despedida de la escena.
		 * Se establece en false el atributo allowedKnock para no permitir que Hammer realice un golpe mientras
		 * no se encuentra la mesa en escena.
		 * Si es que existen los TweenMax de movimiento horizontal, de golpe y de subida, se eliminan.
		 * Se asigna al atributo movePoint la posición del componente Spatial.
		 * Se llama al método updatePoint pasando por parámetro el atributo movePoint.
		 * Se crea un TweenMax para realizar un movimiento desde la posición en que se encuentre Hammer hasta la posición 
		 * en y:0 y la misma coordenada en x en la que se encuentra. Al completarse dicho movimiento se llama al método
		 * goLeft.
		 * 
		 * @param e evento de TableWood.
		 * 
		 * @see updatePoint
		 * 
		 * @see goLeft
		 */		
		public function stopHammer(e:TableWoodGenericEvent):void
		{	
			allowedKnock = false;
			
			tweenHorizontalMove.kill();
			if(tweenKnockMove){
			tweenKnockMove.kill();
			tweenGoUpMove.kill();
			}
			
			movePoint = owner.getProperty(new PropertyReference("@Spatial.position"));
			updatePoint(movePoint);
			tweenGoUpMove = TweenMax.to(movePoint,0.4,{y:0, ease:Linear.easeNone, onComplete:goLeft});
		}
		
		/**
		 * Manejador de evento que se dispara cuando Hammer colisiona con Nail.
		 * El atributo wentDown se establece en true en el método knock. Por lo tanto si se ha realizado un golpe (knock)
		 * se hacen las siguientes acciones:
		 * Se establece en true el atributo collidedWithNail.
		 * Se inicializa el componente sound.
		 * Se destruyen los TweenMax que estén solicitando el método goUp.
		 * Se establece en false el atributo wentDown.
		 * Se llama al método wentDown.
		 * 
		 * @param e
		 * 
		 * @see goUp
		 */		
		public function nailHit(e:CollisionEvent):void
		{	if(wentDown){
				collidedWithNail = true;
				sound = new HammerSoundComponent();
				TweenMax.killDelayedCallsTo(goUp);
				tweenKnockMove.kill();
				wentDown = false;
				goUp();
			}
		
		}
		
		/**
		 * Se crea TweenMax para movimiento de subida de Hammer luego de haber bajado para realizar el golpe. Hammer sube 
		 * desde la posición en que se encuentra hasta la posición con la misma coordenada en x e y en 0. Al completarse
		 * dicho movimiento se llama al método pauseFalse.
		 * Si el atributo collidedWithNail está establecido en true se dispara evento Nail_HIT_EVENT a owner (para que 
		 * otro componente de la misma entidad pueda escuchar).
		 * Si el atributo collidedWithNail está establecido en false (es decir que no se produjo colisión con Nail, por 
		 * lo que Hammer colisionó con TableWood) se dispara evento FLOOR_HIT_EVENT a owner y a mainStage (para que 
		 * componentes de otras entidades lo puedan escuchar).
		 * 
		 * @see updatePoint
		 * 
		 * @see pauseFalse
		 */		
		public function goUp():void{
			updatePoint(knockPoint);
			tweenGoUpMove = TweenMax.to(knockPoint,0.4,{y:0, ease:Linear.easeNone, onComplete:pauseFalse});
			
			if(collidedWithNail){
				if(owner)
					owner.eventDispatcher.dispatchEvent(new HammerGenericEvent(HammerGenericEvent.NAIL_HIT_EVENT));
			}else{
				PBE.mainStage.dispatchEvent(new HammerGenericEvent(HammerGenericEvent.FLOOR_HIT_EVENT));
				if(owner)
					owner.eventDispatcher.dispatchEvent(new HammerGenericEvent(HammerGenericEvent.FLOOR_HIT_EVENT));
			}
		}
		
		/**
		 * Método que realiza movimiento de Hammer hacia posición de partida cuando ingresa una nueva TableWood.
		 * Dicha posición está en x:-220 e y:0.
		 * 
		 */		
		public function goLeft():void
		{
			movePoint = owner.getProperty(new PropertyReference("@Spatial.position"));
			updatePoint(movePoint);
			tweenGoLeft = TweenMax.to(movePoint,0.4,{x:-220, ease:Linear.easeNone});	
		}
		
		/**
		 * Método que cancela la pausa establecida a tweenHorizontalMove en el método knock.
		 * Se permite que Hammer realice golpes.
		 * 
		 */		
		public function pauseFalse():void
		{
			wentDown = false;
			updatePoint(movePoint);
			tweenHorizontalMove.resume();
			allowedKnock=true;
		}
		
		/**
		 * 
		 * @param tickRate
		 * 
		 */		
		override public function onFrame(tickRate:Number):void{
			super.onFrame(tickRate);
			if(owner)
				owner.setProperty(new PropertyReference("@Spatial.position"),point);
		}

		/**
		 * Se remueven los Listeners agregados 
		 * 
		 */				
		override protected function onRemove():void{
			super.onRemove();
			PBE.mainStage.removeEventListener(KeyboardEvent.KEY_DOWN,knock);	
			PBE.mainStage.removeEventListener(TableWoodGenericEvent.TABLEWOOD_TRHOW_EXIT,stopHammer);
			PBE.mainStage.removeEventListener(TableWoodGenericEvent.TABLEWOOD_ENTER_EVENT,move);
		}
	}
}